import { assert } from './assert'


export class CircularList<T> {

    private _capacity: number
    private _data: T[]
    private _head_index: number
    private _length: number

    constructor(capacity: number) {
        this._capacity = capacity
        this._data = new Array<T>(capacity)
        this._head_index = 0
        this._length = 0
    }

    get capacity(): number {
        return this._capacity
    }

    get length(): number {
        return this._length
    }

    get(index: number): T {
        assert(index >= 0 && index < this._length, 'Index out of range')
        return this._data[(this._head_index + index) % this._capacity]!
    }

    *[Symbol.iterator](): IterableIterator<T> {
        for (let i = 0; i < this._length; i++)
            yield this._data[(this._head_index + i) % this._capacity]!
    }

    toArray(): T[] {
        const arr = new Array<T>(this._length)
        for (let i = 0; i < this._length; i++)
            arr[i] = this._data[(this._head_index + i) % this._capacity]!

        return arr
    }

    set(index: number, value: T): void {
        assert(index >= 0 && index < this._length, 'Index out of range')
        this._data[(this._head_index + index) % this._capacity] = value
    }

    /**
     * 把新的元素添加到队列的末尾。
     */
    push(value: T): void {
        if (this._length < this._capacity) {
            this._data[(this._head_index + this._length) % this._capacity] = value
            this._length++
        }
        else {
            this._data[this._head_index] = value
            this._head_index = (this._head_index + 1) % this._capacity
        }
    }

    /**
     * 弹出队列末尾的元素。
     */
    pop(): T | undefined {
        if (this._length === 0)
            return undefined

        const value = this._data[(this._head_index + this.length - 1) % this._capacity]
        this._length--
        return value
    }

    /**
     * 把新元素添加在队列头部。
     */
    prepend(value: T): void {
        this._head_index--
        if (this._head_index < 0)
            this._head_index += this._capacity

        this._data[this._head_index] = value
        
        if (this._length < this._capacity)
            this._length++
    }

    /**
     * 弹出队列头部的元素。
     */
    shift(): T | undefined {
        if (this._length === 0)
            return undefined

        const value = this._data[this._head_index]
        this._head_index = (this._head_index + 1) % this._capacity
        this._length--
        return value
    }
}